#include "StdAfx.hpp"
#include "ResourceObject.hpp"


//HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
// ResourceLoadingJob

class ResourceLoadingJob : public BkgJob
{
public:
	ResourceLoadingJob(ResourceObject *Res, TYPE Type);
	virtual ~ResourceLoadingJob();

protected:
	virtual void OnWork();
	virtual void OnWorkDone();

private:
	ResourceObject *m_Res;
};


ResourceLoadingJob::ResourceLoadingJob(ResourceObject *Res, TYPE Type) :
BkgJob(Type, MODE_JOINABLE),
m_Res(Res)
{
}

ResourceLoadingJob::~ResourceLoadingJob()
{
}

void ResourceLoadingJob::OnWork()
{
	m_Res->OnLoadBkg();
}

void ResourceLoadingJob::OnWorkDone()
{
	if (GetSavedError() != NULL)
	{
		m_Res->m_SavedError.reset(new common::Error(*GetSavedError()));
		m_Res->m_State = ResourceObject::STATE_LOADED_ERROR;
		ResourceObject::m_LoadedResourceCount++;
		m_Res->m_SavedError->Push(Format("Exception caught in ResourceLoadingJob.OnWorkDone for resource \"#\"") % m_Res->GetName());

		LogError(LOG_RESMNGR, *m_Res->m_SavedError.get());

		return;
	}

	try
	{
		m_Res->OnLoadAfterBkg();
		m_Res->m_State = ResourceObject::STATE_LOADED;
		ResourceObject::m_LoadedResourceCount++;
	}
	catch (common::Error &e)
	{
		m_Res->m_SavedError.reset(new common::Error(e));
		m_Res->m_State = ResourceObject::STATE_LOADED_ERROR;
		m_Res->m_SavedError->Push(Format("Exception caught in ResourceLoadingJob.OnWorkDone for resource \"#\"") % m_Res->GetName());
		ResourceObject::m_LoadedResourceCount++;

		LogError(LOG_RESMNGR, *m_Res->m_SavedError.get());
	}
}


//HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
// ResourceObject

uint ResourceObject::m_ResourceCount = 0;
uint ResourceObject::m_LoadedResourceCount = 0;

ResourceObject::ResourceObject()
: m_State(STATE_UNLOADED)
, m_Job(NULL)
{
	m_ResourceCount++;
}

ResourceObject::~ResourceObject()
{
	if (m_Job) { m_Job->Join(); delete m_Job; }
	m_ResourceCount--;
}

void ResourceObject::Load()
{
	BeginLoading();
	if (m_State == STATE_LOADING)
		WaitForLoaded();
}

void ResourceObject::BeginLoading()
{
	if (m_State != STATE_UNLOADED) return;

	bool UseBkg;
	BkgJob::TYPE BkgType;
	GetLoadType(&UseBkg, &BkgType);

	try
	{
		OnLoad();
	}
	catch (common::Error &e)
	{
		e.Push("Exception caught in ResourceObject.BeginLoading for: " + GetName(), __TFILE__, __LINE__);
		m_SavedError.reset(new common::Error(e));
		m_State = STATE_LOADED_ERROR;
		m_LoadedResourceCount++;

		LogError(LOG_RESMNGR, e);

		return;
	}

	if (UseBkg)
	{
		if (m_Job) { m_Job->Join(); delete m_Job; }
		m_Job = new ResourceLoadingJob(this, BkgType);
		m_Job->SetPriority(m_Priority);
		g_BkgJobManager->AddJob(m_Job);

		m_State = STATE_LOADING;
	}
	else
	{
		m_State = STATE_LOADED;
		m_LoadedResourceCount++;
	}
}

void ResourceObject::Unload()
{
	WaitForLoaded();

	if (m_State >= STATE_LOADED)
	{
		m_LoadedResourceCount--;
		OnUnload();
		m_State = STATE_UNLOADED;
	}
}

void ResourceObject::WaitForLoaded()
{
	if (m_Job)
	{
		m_Job->Join();
		delete m_Job;
		m_Job = NULL;
	}
}
